package org.design.singleton;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 一个非常简单的单例模式 
 * 1. 私有静态的一个自己 
 * 2. 构造函数私有，这样的话，就不能随意new实例了 
 * 3. 用一个静态方法获得一个实例
 * 
 * @author chenxianpeng
 *
 */
public class SimpleSingleton1 implements Serializable {
	private static SimpleSingleton1 _instance = null;

	private SimpleSingleton1() {
		// TODO Auto-generated constructor stub
	}

	public static SimpleSingleton1 getInstance() {
		if (_instance == null) {
			_instance = new SimpleSingleton1();
		}
		return _instance;
	}

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException {
		// TODO Auto-generated method stub
		// 大部分时候，我们一般情况下，代码就写到这里了。
		SimpleSingleton1 a1 = SimpleSingleton1.getInstance();
		SimpleSingleton1 a2 = SimpleSingleton1.getInstance();
		System.out.println("a1=" + a1);
		System.out.println("a2=" + a2);
		System.out.println("equal?" + (a1 == a2));

		// 如果碰到反射呢？
		// 通过反射的方式直接调用私有构造器（通过在构造器里抛出异常可以解决此漏洞）
		Class<SimpleSingleton1> clazz = 
				(Class<SimpleSingleton1>) Class.forName(
				"org.design.singleton.SimpleSingleton1");
		Constructor<SimpleSingleton1> c = 
				clazz.getDeclaredConstructor(null);
//		clazz.getConstructor(parameterTypes)
		c.setAccessible(true); // 跳过权限检查
		SimpleSingleton1 ss3 = c.newInstance();
		SimpleSingleton1 ss4 = c.newInstance();
		System.out.println("ss3=" + ss3); // ss3，ss4不是同一个对象
		System.out.println("ss4=" + ss4);
		
		//如果碰到序列化 反序列化呢？
		//我们的类首先要支持序列化，不支持的话，就无所谓这个问题了。
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(a1);  
        oos.close();  
        ByteArrayInputStream bais = new ByteArrayInputStream(
        		baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        SimpleSingleton1 ss5 = (SimpleSingleton1) ois.readObject();
        ois.close();
        System.out.println("a1=" + a1);
        System.out.println("ss5=" + ss5);
	}

}
